import router, { asyncRoutes, constantRoutes } from '@/router'
import {
  tenantLayout,
  tenantRoutes,
  accountRoutes
} from '@/router/modules/adminManage'
import { deepClone } from '@/utils'
import { getPrincipleMenu, getPrincipleUI } from '@/api/tenant'

/**
 * Use meta.role to determine if the current user has permission
 * @param roles
 * @param route
 */
function hasPermission(roles, route) {
  if (route.meta && route.meta.roles) {
    return roles.some(role => route.meta.roles.includes(role))
  } else {
    return true
  }
}

/**
 * Filter asynchronous routing tables by recursion
 * @param routes asyncRoutes
 * @param roles
 */
export function filterAsyncRoutes(routes, roles) {
  const res = []

  routes.forEach(route => {
    const tmp = { ...route }
    if (hasPermission(roles, tmp)) {
      if (tmp.children) {
        tmp.children = filterAsyncRoutes(tmp.children, roles)
      }
      res.push(tmp)
    }
  })

  return res
}

export function judgeRouterPermission(localRoute, responsePermission) {
  const res = []
  localRoute.forEach(route => {
    const tmp = { ...route }
    const path = route.path.includes('/') ? route.path.substring(1) : route.path
    if (responsePermission.includes(path)) {
      if (tmp.children) {
        tmp.children = judgeRouterPermission(tmp.children, responsePermission)
      }
      res.push(tmp)
    }
  })
  return res.filter(item => item.children && item.children.length || item.children === undefined)
}

const state = {
  routes: [],
  addRoutes: [],
  accessList: [],
  uiPermissionList: {}
}

const mutations = {
  SET_ROUTES: (state, routes) => {
    state.addRoutes = routes
    state.routes = constantRoutes.concat(routes)
  },
  SET_ACCESS_LIST: (state, list) => {
    state.accessList = list
  },
  INIT_UI_PERMISSION_LIST: (state, value) => {
    state.uiPermissionList = value
  },
  SET_UI_PERMISSION_LIST_KEY: (state, { path, type, value }) => {
    state.uiPermissionList[path][type] = value
  }
}

const actions = {
  generateRoutes({ commit }, roles) {
    return new Promise(resolve => {
      let accessedRoutes
      if (roles.includes('admin')) {
        accessedRoutes = asyncRoutes || []
      } else {
        accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
      }
      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  },
  judgeAdminRoleMenuList({ commit }, data) {
    const { tenant_accounts } = this.getters
    return new Promise((resolve, reject) => {
      const asyncMenu = deepClone(asyncRoutes)
      const tenantMenu = deepClone(tenantLayout)
      tenantMenu.children = []
      // 多租户系统是本地注册时,则有账套管理功能
      tenant_accounts.selfRegister && tenantMenu.children.push(tenantRoutes[0])
      // 账套管理员,拥有资源扫描权限
      tenant_accounts.accountAdmin && tenantMenu.children.push(tenantRoutes[1])
      // 当超管拥有账套管理员角色
      tenantMenu.children.push(...accountRoutes)
      // 判断当前路由表中是否已存在授权管理菜单,如果不存在,则添加
      if (asyncMenu.map(item => item.path).every(item => item !== tenantMenu.path) && tenantMenu.children.length > 0) {
        const len = asyncMenu.length
        asyncMenu.splice(len - 1, 0, tenantMenu)
      }
      commit('SET_ROUTES', asyncMenu)
      router.addRoutes(asyncMenu)
      return resolve()
    })
  },
  fetchUserMenuPermission({ commit }) {
    const { tenant_accounts } = this.getters
    return new Promise((resolve, reject) => {
      const data = {
        systemId: process.env.VUE_APP_client_id,
        permissionParentId: 'ROOT',
        tenantId: tenant_accounts.tenantId,
        accountId: tenant_accounts.accountId
      }
      const tenantInfo = `${tenant_accounts.tenantId}:${tenant_accounts.accountId}`
      getPrincipleMenu({ data, tenantInfo }).then(res => {
        let data = res.data.filter(item => item.permissionVisible && item.systemId === process.env.VUE_APP_client_id)
        const obj = {}
        data = data.map(item => {
          // 初始化当前页面的UI授权列表信息
          obj[item.permissionName] = {}
          obj[item.permissionName].parentId = item.permissionId
          // 拼接路由授权列表信息
          const tmp = item.permissionName.split('/').slice(1)
          return tmp[tmp.length - 1]
        })
        const accessed = judgeRouterPermission(asyncRoutes, data)
        if (tenant_accounts.accountAdmin || tenant_accounts.tenantAdmin) {
          tenantLayout.children = []
          // 多租户系统是本地注册时,则有账套管理功能
          tenant_accounts.selfRegister && tenantLayout.children.push(tenantRoutes[0])
          // 账套管理员,拥有资源扫描权限
          tenant_accounts.accountAdmin && tenantLayout.children.push(tenantRoutes[1])
          // 账套管理员,拥有其他管理权限权限
          tenant_accounts.accountAdmin && tenantLayout.children.push(...accountRoutes)
          tenantLayout.children.length > 0 && accessed.push(tenantLayout)
        }
        accessed.push({ path: '*', redirect: '/404', hidden: true })
        // 初始化UI 授权列表
        commit('INIT_UI_PERMISSION_LIST', obj)
        // 设置服务器授权列表
        commit('SET_ACCESS_LIST', data)
        // 设置授权路由
        commit('SET_ROUTES', accessed)
        resolve(accessed)
      }).catch(error => {
        reject(error)
      })
    })
  },
  fetchUserUiPermission({ commit }, path) {
    const { uiPermissionList } = this.state.permission
    const tenant_accounts = this.getters
    return new Promise((resolve, reject) => {
      // 排除同步菜单项
      if (uiPermissionList[ path ] === undefined || uiPermissionList[ path ].permissionEnable) return resolve()
      getPrincipleUI({
        tenantId: tenant_accounts.tenantId,
        accountId: tenant_accounts.accountId,
        systemId: process.env.VUE_APP_client_id,
        permissionParentId: uiPermissionList[path].parentId
      }).then(res => {
        const types = ['permissionEnable', 'permissionVisible', 'permissionReadOnly']
        types.forEach(type => {
          // 过滤未授权的资源id
          const data = res.data.filter(item => item[type]).map(item => item.permissionName)
          commit('SET_UI_PERMISSION_LIST_KEY', { path, type, value: data })
        })
        resolve(res.data)
      }).catch(error => {
        reject(error)
      })
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}
